// -----------------------------------------------------------------------------
// This source file is part of Matrix Platform
// 	(Universal .NET Software Development Platform)
// For the latest info, see http://www.matrixplatform.com
// 
// Copyright (c) 2009-2010, Ingenious Ltd
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Matrix.Common.Core.Collections
{
    /// <summary>
    /// Hot swapping.
    /// 
    /// To evade locking - when adding new items, simply replace the list with a new one.
    /// </summary>
    [Serializable]
    public class HotSwapList<TType> : IList<TType>
    {
        volatile List<TType> _instance = new List<TType>();

        public List<TType> CurrentInstance
        {
            get
            {
                return _instance;
            }
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        public HotSwapList()
        {
        }

        /// <summary>
        /// This allows to quickly capture a read only version of the 
        /// collection that can be further used as needed in any scenario.
        /// </summary>
        /// <returns></returns>
        public ReadOnlyCollection<TType> AsReadOnly()
        {
            return _instance.AsReadOnly();
        }

        /// <summary>
        /// Add item only if it does not already exist.
        /// </summary>
        /// <param name="item"></param>
        /// <returns>True if the add was performed, or false if it already exists.</returns>
        public bool AddUnique(TType item)
        {
            lock (this)
            {
                if (_instance.Contains(item))
                {
                    return false;
                }

                Add(item);
            }

            return true;
        }

        /// <summary>
        /// Try to obtain a value with this index, return false if we fail and no modification to value done.
        /// </summary>
        /// <param name="index">The index of the item retrieved.</param>
        /// <param name="value">The resulting retrieve value.</param>
        /// <returns>True if the value was retrieved, otherwise false.</returns>
        public bool TryGetValue(int index, ref TType value)
        {
            List<TType> instance = _instance;
            if (instance.Count > index)
            {
                value = instance[index];
                return true;
            }

            return false;
        }

        /// <summary>
        /// Sort the items in the collection (must implement IComparable).
        /// </summary>
        public bool Sort()
        {
            if (ReflectionHelper.IsTypeImplementingInterface(typeof(TType), typeof(IComparable)) == false)
            {
                return false;
            }

            lock (this)
            {
                SortedList<TType, TType> items = new SortedList<TType, TType>();
                foreach (TType item in this._instance)
                {
                    items.Add(item, item);
                }

                this.SetToRange(CommonHelper.EnumerableToArray(items.Values));
            }

            return true;
        }

        /// <summary>
        /// Clear all items and add the current badge.
        /// </summary>
        public void SetToRange(IEnumerable<TType> items)
        {
            lock (this)
            {
                List<TType> instance = new List<TType>();
                instance.AddRange(items);
                _instance = instance;
            }
        }

        public void AddRange(IEnumerable<TType> items)
        {
            lock (this)
            {
                List<TType> instance = new List<TType>(_instance);
                instance.AddRange(items);
                _instance = instance;
            }
        }
        
        /// <summary>
        /// Remove all instances that are equal, or the same as, this item.
        /// </summary>
        /// <returns>Count of items removed.</returns>
        public int RemoveAll(TType item)
        {
            int result = 0;
            lock (this)
            {
                List<TType> instance = new List<TType>(_instance);
                
                while (instance.Remove(item))
                {
                    result++;
                }

                if (result != 0)
                {
                    _instance = instance;
                }
            }

            return result;
        }


        #region IList<TType> Members

        public int IndexOf(TType item)
        {
            return _instance.IndexOf(item);
        }

        public void Insert(int index, TType item)
        {
            lock (this)
            {
                List<TType> items = new List<TType>(_instance);
                items.Insert(index, item);
                _instance = items;
            }
        }

        /// <summary>
        /// Implementation has internal check security,
        /// so no exceptions occur.
        /// </summary>
        /// <param name="index"></param>
        public void RemoveAt(int index)
        {
            lock (this)
            {
                if (_instance.Count > index)
                {
                    List<TType> items = new List<TType>(_instance);
                    items.RemoveAt(index);
                    _instance = items;
                }
            }
        }

        /// <summary>
        /// *Warning* setting a value if very slow, since it redoes the hotswaps
        /// the entire collection too, so use with caution.
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public TType this[int index]
        {
            get
            {
                return _instance[index];
            }

            set
            {
                lock (this)
                {
                    List<TType> items = new List<TType>(_instance);
                    items[index] = value;
                    _instance = items;
                }
            }
        }

        #endregion

        #region ICollection<TType> Members

        public void Add(TType item)
        {
            lock (this)
            {
                List<TType> items = new List<TType>(_instance);
                items.Add(item);
                _instance = items;
            }
        }

        public bool Remove(TType item)
        {
            lock (this)
            {
                if (_instance.Contains(item) == false)
                {
                    return false;
                }

                List<TType> items = new List<TType>(_instance);
                items.Remove(item);
                _instance = items;
            }

            return true;
        }

        public void Clear()
        {
            lock (this)
            {
                _instance = new List<TType>();
            }
        }

        public bool Contains(TType item)
        {
            return _instance.Contains(item);
        }

        public void CopyTo(TType[] array, int arrayIndex)
        {
            _instance.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return _instance.Count; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }


        #endregion

        #region IEnumerable<TType> Members

        public IEnumerator<TType> GetEnumerator()
        {
            return _instance.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _instance.GetEnumerator();
        }

        #endregion
    }
}
